package com.paradogs.demo.client;

import com.paradogs.demo.client.demo.Client;
import com.paradogs.demo.client.pojo.CGLogin;
import com.paradogs.framework.common.pojo.cg.CGGateLogin;
import com.paradogs.framework.common.pojo.gc.GCApplyGate;
import com.paradogs.framework.core.msg.ByteData;
import com.paradogs.framework.core.msg.R;
import com.paradogs.framework.core.netty.PRCodec;
import com.paradogs.framework.core.utils.ProtoUtils;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import io.netty.handler.codec.LengthFieldPrepender;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

/**
 * @author: yumi
 * @date: 2023/7/31  23:25
 * @Description: TODO
 */
@Slf4j
@SpringBootApplication
public class DemoClientApplication {
    public static void main(String[] args) throws InterruptedException {
        SpringApplication.run(DemoClientApplication.class, args);

        Bootstrap client = new Bootstrap()
                .group(new NioEventLoopGroup())
                .channel(NioSocketChannel.class)
                .handler(new ChannelInitializer<NioSocketChannel>() {
                    @Override
                    protected void initChannel(NioSocketChannel channel) throws Exception {
                        channel.pipeline().addLast(new LengthFieldBasedFrameDecoder(
                                65534,
                                0,
                                2,
                                0,
                                2));

                        channel.pipeline().addLast(new LengthFieldPrepender(2));

                        channel.pipeline().addLast(new PRCodec());

                        // addLast() 加入越晚的出栈时越先执行
                        channel.pipeline().addLast(new SimpleChannelInboundHandler<ByteData>() {
                            @Override
                            protected void channelRead0(ChannelHandlerContext ctx, ByteData msg) throws Exception {
                                GCApplyGate result = ProtoUtils.decode(msg.getDataBytes(), GCApplyGate.class);
                                log.info("Receive: {}", result);

                                Bootstrap client = new Bootstrap()
                                        .group(new NioEventLoopGroup())
                                        .channel(NioSocketChannel.class)
                                        .handler(new ChannelInitializer<NioSocketChannel>() {
                                            @Override
                                            protected void initChannel(NioSocketChannel channel) throws Exception {
                                                channel.pipeline().addLast(new LengthFieldBasedFrameDecoder(
                                                        65534,
                                                        0,
                                                        2,
                                                        0,
                                                        2));

                                                channel.pipeline().addLast(new LengthFieldPrepender(2));

                                                channel.pipeline().addLast(new PRCodec());

                                                // addLast() 加入越晚的出栈时越先执行
                                                channel.pipeline().addLast(new SimpleChannelInboundHandler<ByteData>() {
                                                    @Override
                                                    protected void channelRead0(ChannelHandlerContext ctx, ByteData msg) throws Exception {
                                                        if (msg.getMsgHeader().getRoute().equals("syncData")) {
                                                            R result = ProtoUtils.decode(msg.getDataBytes(), R.class);
                                                            log.info("Receive: {}", result);
                                                        } else {
                                                            log.info("Receive: {}", msg);
                                                        }
                                                    }
                                                });
                                            }
                                        });
                                Channel gateChannel = client.connect(result.getHost(), result.getPort()).sync().channel();
                                log.info("Connect Gate success");
                                Client.send(gateChannel, "gate|login", new CGGateLogin(result.getToken()));

                                Thread.sleep(1000);
                                new Thread(new Runnable() {
                                    @SneakyThrows
                                    @Override
                                    public void run() {
                                        while (true) {
                                            Client.send(gateChannel, "logic|role.updateData", new CGGateLogin("123"));
                                            Thread.sleep(199999000);
                                        }
                                    }
                                }).start();

                            }
                        });
                    }
                });

        Channel channel = client.connect("localhost", 80).sync().channel();

        Client.send(channel, "login|login", new CGLogin("yumi", "123"));
    }
}
